package com.yy.auth.server.config;

import com.yy.auth.server.config.filter.TokenEndpointLogFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
import org.springframework.web.cors.CorsConfiguration;

/**
 * @Description 授权服务器-安全配置
 * @Date 2025/10/10 上午10:13
 * @Author yanglin
 **/
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

    //@Bean
    //public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    //    http
    //            .authorizeHttpRequests(authorize -> authorize
    //                    .requestMatchers("/assets/**", "/.well-known/openid-configuration", "/oauth2/jwks").permitAll()
    //                    .anyRequest().authenticated()
    //            )
    //            .formLogin(form -> form
    //                    .loginPage("/login")
    //                    .permitAll()
    //            );
    //    return http.build();
    //}

    /*@Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http, HttpSessionRequestCache requestCache) throws Exception {
        // 应用默认的OAuth2授权服务器配置
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        // 保存授权请求
        http.formLogin(form -> form
                .loginPage("/login") // GET /login 显示登录表单
                //.loginProcessingUrl("/login") // POST /login 处理登录请求
                //.usernameParameter("username")
                //.passwordParameter("password")
                .successHandler((request, response, authentication) -> {
                    logger.debug("[SSO-AUTH-SERVER] Authentication successful for user: {}", authentication.getName());
                    // 从会话中获取保存的授权请求
                    SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
                    if (savedRequest != null) {
                        logger.debug("[SSO-AUTH-SERVER] Redirecting to saved request: {}", savedRequest.getRedirectUrl());
                        // 重定向回原始授权请求
                        String redirectUrl = savedRequest.getRedirectUrl();
                        // 清除保存的请求
                        requestCache.removeRequest(request, response);
                        // 重定向到原始授权请求
                        response.sendRedirect(redirectUrl);
                    } else {
                        logger.debug("[SSO-AUTH-SERVER] No saved request found, redirecting to default URL");
                        // 回退到默认授权端点
                        response.sendRedirect("/oauth2/authorize");
                    }
                })
                .failureHandler((request, response, authentication) -> {
                    logger.debug("[SSO-AUTH-SERVER] Authentication failure for user: {}", authentication.getAuthenticationRequest().getDetails());
                })
                .permitAll()
        );
        // 配置OIDC发现端点允许GET请求，解决/.well-known/openid-configuration返回错误问题
        http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                .oidc(oidc -> oidc
                        .providerConfigurationEndpoint(providerConfig -> {
                            // 不需要显式设置 allowGetRequests，默认已允许
                            // 可以添加其他自定义配置
                        })
                );

        // 临时禁用 CSRF 进行测试
        //http.csrf(csrf -> csrf.disable());
        // 配置异常处理
        http
                .exceptionHandling(exceptions -> exceptions
                        .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
                );

        // 允许公开访问发现端点和JWKS端点
        // Can't configure mvcMatchers after anyRequest ==>确保 anyRequest()是最后一个匹配器
        // 使用自定义匹配器确保 anyRequest() 是最后一个
        //http.authorizeHttpRequests(authorize -> authorize
        //        .requestMatchers(publicEndpointsMatcher()).permitAll()
        //        .anyRequest().authenticated()
        //);
        return http.formLogin(Customizer.withDefaults()).build();
        //return http.build();

    }

    *//**
     * 创建自定义请求匹配器
     * @return
     *//*
    private RequestMatcher publicEndpointsMatcher() {
        return new OrRequestMatcher(
                new AntPathRequestMatcher("/.well-known/openid-configuration"),
                new AntPathRequestMatcher("/oauth2/jwks"),
                new AntPathRequestMatcher("/login"),
                new AntPathRequestMatcher("/error")
        );
    }



    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.builder()
                .username("admin")
                .password(passwordEncoder().encode("123456"))
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    *//**
     * 会话请求缓存
     * @return
     *//*
    @Bean
    public HttpSessionRequestCache httpSessionRequestCache() {
        HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
        requestCache.setCreateSessionAllowed(true);
        return requestCache;
    }

    */

    /**
     * 会话管理配置
     *
     * @return
     *//*
    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer serializer = new DefaultCookieSerializer();
        serializer.setCookieName("SESSION");
        serializer.setSameSite("Lax"); // 允许跨站请求
        serializer.setUseHttpOnlyCookie(true);
        serializer.setCookiePath("/");
        return serializer;
    }*/

    //@Bean
    //@Order(Ordered.HIGHEST_PRECEDENCE)
    //public SecurityFilterChain authorizationServerSecurityFilterChain(
    //        HttpSecurity http,
    //        AuthenticationManager authenticationManager) throws Exception {
    //
    //    // 应用默认的OAuth2授权服务器配置
    //    OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
    //    // 配置OIDC发现端点允许GET请求，解决/.well-known/openid-configuration返回错误问题 ？？？？
    //    http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
    //            .oidc(oidc -> {
    //            });
    //    // 保存授权请求
    //    http.requestCache(cache -> cache
    //            .requestCache(new HttpSessionRequestCache())
    //    );
    //    //        .formLogin(form -> form
    //    //        .loginPage("/login")
    //    //        .successHandler((request, response, authentication) -> {
    //    //            logger.info("Authentication successful for user: {}", authentication.getName());
    //    //            // 从会话中获取保存的授权请求
    //    //            SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
    //    //            if (savedRequest != null) {
    //    //                logger.info("Redirecting to saved request: {}", savedRequest.getRedirectUrl());
    //    //            } else {
    //    //                logger.warn("No saved request found, redirecting to default URL");
    //    //            }
    //    //            if (savedRequest != null) {
    //    //                // 重定向回原始授权请求
    //    //                String redirectUrl = savedRequest.getRedirectUrl();
    //    //                response.sendRedirect(redirectUrl);
    //    //            } else {
    //    //                // 回退到默认授权端点
    //    //                response.sendRedirect("/oauth2/authorize");
    //    //            }
    //    //        })
    //    //);
    //
    //    http.formLogin(form -> form
    //            .loginPage("/login") // GET /login 显示登录表单
    //            .successHandler((request, response, authentication) -> {
    //                logger.debug("[SSO-AUTH-SERVER] Authentication successful for user: {}", authentication.getName());
    //                // 从会话中获取保存的授权请求
    //                SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
    //                if (savedRequest != null) {
    //                    logger.debug("[SSO-AUTH-SERVER] Redirecting to saved request: {}", savedRequest.getRedirectUrl());
    //                    // 重定向回原始授权请求
    //                    String redirectUrl = savedRequest.getRedirectUrl();
    //                    // 重定向到原始授权请求
    //                    response.sendRedirect(redirectUrl);
    //                } else {
    //                    logger.debug("[SSO-AUTH-SERVER] No saved request found, redirecting to default URL");
    //                    // 回退到默认授权端点
    //                    response.sendRedirect("/oauth2/authorize");
    //                }
    //            })
    //            .failureHandler((request, response, authentication) -> {
    //                logger.debug("[SSO-AUTH-SERVER] Authentication failure for user: {}", authentication.getAuthenticationRequest().getDetails());
    //            })
    //            .permitAll()
    //    );
    //
    //    // 配置异常处理
    //    http
    //            .exceptionHandling(exceptions -> exceptions
    //                    .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
    //            );
    //
    //    // 允许公开访问发现端点和JWKS端点
    //    // Can't configure mvcMatchers after anyRequest ==>确保 anyRequest()是最后一个匹配器
    //    //http.authorizeHttpRequests(authorize -> authorize
    //    //        .requestMatchers(
    //    //                "/.well-known/openid-configuration",
    //    //                "/oauth2/jwks"
    //    //        ).permitAll()
    //    //        .anyRequest().authenticated()
    //    //);
    //
    //    // 在安全过滤器链中设置 AuthenticationManager
    //    http.authenticationManager(authenticationManager);
    //    // 临时禁用 CSRF 进行测试
    //    http.csrf(csrf -> csrf.disable());
    //    return http.formLogin(Customizer.withDefaults()).build();
    //    //return http.build();
    //}
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http, HttpSessionRequestCache requestCache, TokenEndpointLogFilter tokenEndpointLogFilter) throws Exception {
        // 应用默认的OAuth2授权服务器配置
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        // 令牌端点日志
        http.addFilterBefore(tokenEndpointLogFilter, UsernamePasswordAuthenticationFilter.class);
        // 令牌端点认证
        http.oauth2ResourceServer(oauth2 -> oauth2
                .jwt(Customizer.withDefaults())
        );
        // 配置OIDC发现端点允许GET请求，解决/.well-known/openid-configuration返回错误问题
        http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                .oidc(oidc -> {
                });
        // 保存授权请求
        http.requestCache(cache -> cache
                .requestCache(new HttpSessionRequestCache())
        );
        // 跨域支持
        http.cors(cors -> cors
                        .configurationSource(request -> {
                            CorsConfiguration config = new CorsConfiguration();
                            config.addAllowedOrigin("http://localhost:8081");
                            config.addAllowedOrigin("http://localhost:8082");
                            config.addAllowedMethod("*");
                            config.addAllowedHeader("*");
                            config.setAllowCredentials(true);
                            return config;
                        })
                );
        http.formLogin(form -> form
                .loginPage("/login") // GET /login 显示登录表单
                .successHandler((request, response, authentication) -> {
                    logger.debug("[SSO-AUTH-SERVER] Authentication successful for user: {}", authentication.getName());
                    // 从会话中获取保存的授权请求
                    SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
                    if (savedRequest != null) {
                        logger.debug("[SSO-AUTH-SERVER] Redirecting to saved request: {}", savedRequest.getRedirectUrl());
                        // 重定向回原始授权请求
                        String redirectUrl = savedRequest.getRedirectUrl();
                        // 清除保存的请求
                        requestCache.removeRequest(request, response);
                        // 重定向到原始授权请求
                        response.sendRedirect(redirectUrl);
                    } else {
                        logger.debug("[SSO-AUTH-SERVER] No saved request found, redirecting to default URL");
                        // 回退到默认授权端点
                        response.sendRedirect("/oauth2/authorize");
                    }
                })
                .failureHandler((request, response, authentication) -> {
                    logger.debug("[SSO-AUTH-SERVER] Authentication failure for user: {}", authentication.getAuthenticationRequest().getDetails());
                })
                .permitAll()
        );

        // 配置异常处理
        http.exceptionHandling(exceptions -> exceptions
                        .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
                        .accessDeniedHandler((request, response, accessDeniedException) -> {
                            logger.error("[SSO-AUTH-SERVER]  Access denied: {}", accessDeniedException.getMessage());
                            response.sendRedirect("/login?error=access_denied");
                        })
                );

        // 允许公开访问发现端点和JWKS端点
        // Can't configure mvcMatchers after anyRequest ==>确保 anyRequest()是最后一个匹配器
        // 临时禁用 CSRF 进行测试
        http.csrf(csrf -> csrf.disable());
        return http.build();
    }

    @Bean
    @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(
            HttpSecurity http,
            AuthenticationManager authenticationManager) throws Exception {
        http
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/", "/public/**", "/login").permitAll()
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .loginPage("/login")
                        .permitAll()
                )
                .authenticationManager(authenticationManager);
        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.builder()
                .username("admin")
                .password(passwordEncoder().encode("123456"))
                .roles("USER", "OAUTH2_CLIENT")
                .build();
        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    /**
     *  强制使用 BCrypt 编码
     * @return
     */
    //@Bean
    //public PasswordEncoder passwordEncoder() {
    //    return new BCryptPasswordEncoder() {
    //        @Override
    //        public String encode(CharSequence rawPassword) {
    //            if (rawPassword.toString().startsWith("{bcrypt}")) {
    //                return super.encode(rawPassword);
    //            }
    //            return "{bcrypt}" + super.encode(rawPassword);
    //        }
    //
    //        @Override
    //        public boolean matches(CharSequence rawPassword, String encodedPassword) {
    //            // 移除前缀
    //            if (encodedPassword.startsWith("{bcrypt}")) {
    //                encodedPassword = encodedPassword.substring(8);
    //            }
    //            return super.matches(rawPassword, encodedPassword);
    //        }
    //    };
    //}
    /**
     * 会话请求缓存
     *
     * @return
     */
    @Bean
    public HttpSessionRequestCache httpSessionRequestCache() {
        HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
        requestCache.setCreateSessionAllowed(true);
        return requestCache;
    }

    /**
     * 会话管理配置
     *
     * @return
     */
    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer serializer = new DefaultCookieSerializer();
        serializer.setCookieName("SESSION");
        serializer.setSameSite("Lax"); // 允许跨站请求
        serializer.setUseHttpOnlyCookie(true);
        serializer.setCookiePath("/");
        return serializer;
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService());
        provider.setPasswordEncoder(passwordEncoder());
        return provider;
    }

    /**
     * 显式配置 AuthenticationManager
     *
     * @param http
     * @param authenticationProvider
     * @return
     * @throws Exception
     */

    @Bean
    public AuthenticationManager authenticationManager(
            HttpSecurity http,
            AuthenticationProvider authenticationProvider) throws Exception {

        AuthenticationManagerBuilder authenticationManagerBuilder =
                http.getSharedObject(AuthenticationManagerBuilder.class);

        authenticationManagerBuilder
                .authenticationProvider(authenticationProvider);

        return authenticationManagerBuilder.build();
    }
}
